home *** CD-ROM | disk | FTP | other *** search
- Subject: v22i042: NN Newsreader, release 6.4, Part07/21
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 39dcb800 39e05c76 44c3ba86 18e5775a
-
- Submitted-by: "Kim F. Storm" <storm@texas.dk>
- Posting-number: Volume 22, Issue 42
- Archive-name: nn6.4/part07
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: man/nn.1.B master.c
- # Wrapped by storm@texas.dk on Sun May 6 18:19:31 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 7 (of 22)."'
- if test -f 'man/nn.1.B' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'man/nn.1.B'\"
- else
- echo shar: Extracting \"'man/nn.1.B'\" \(32572 characters\)
- sed "s/^X//" >'man/nn.1.B' <<'END_OF_FILE'
- X.\" BEGINPART B
- X.SH FILE NAME EXPANSION
- XWhen the save commands prompts for a file name, the following file
- Xname expansions are performed on the file name you enter:
- X.TP
- X\fB+\fP\fIfolder\fP
- XThe
- X.B +
- Xis replaced by the contents of the
- X.B folder
- Xvariable (default value "~/News/") resulting in the name of a file in the
- X.I folder
- X.IR directory .
- XExamples:
- X.br
- X +emacs, +nn, +sources/shar/nn
- X.TP
- X\fB+\fP
- XA single plus is replaced by the expansion of the file name contained in the
- X.B default-save-file
- Xvariable.
- X.TP
- X\fB~/\fP\fIfile\fP
- XThe
- X.B ~
- Xis replaced by the contents of the environment variable HOME, i.e. the
- Xpath name of your home directory.
- XExamples:
- X.br
- X ~/News/emacs, ~/News/nn, ~/src/shar/nn
- X.TP
- X\fB|\fP\fIcommand-line\fP
- XInstead of writing to a file, the articles are piped to the given
- Xshell (/bin/sh) command-line. Each save or write command will create a
- Xseparate pipe, but all articles saved or written in one command (in
- Xselection mode) are given
- Xas input to the same shell command. Example:
- X.br
- X | pr | lp
- X.br
- XThis will print the articles on the printer after they have been piped
- Xthrough pr.
- X It is possible to create separate pipes for each saved article by
- Xusing a double pipe symbol in the beginning of the command, e.g.
- X.br
- X || cd ~/src/nn ; patch
- X.br
- X.LP
- XThe following symbols are expanded in a file name or command:
- X.TP
- X.B $F
- Xwill be expanded to the name of the current group with the periods
- Xreplaced by slashes, e.g. rec/music/synth.
- X.TP
- X.B $G
- Xwill be expanded to the name of the current group.
- X.TP
- X.B $L
- Xwill be expanded to the \fIlast component\fP of the name of the
- Xcurrent group. You may use this to create default save file names
- Xlike +src/$L in the comp.sources groups.
- X.TP
- X.B $N
- Xwill be expanded to the (local) article number, e.g. 1099. In
- Xselection mode it is only allowed at the end of the file name!
- X.TP
- X.B $(VAR)
- Xis replaced by the string value of the environment variable \fIVAR\fP.
- X.LP
- XUsing these symbols, a simple naming scheme for `default folder name' is
- X.B +$G
- Xwhich will use the group name as folder name. Another possibility is
- X.BR +$F/$N .
- X.LP
- XAs mentioned above, you can also instruct \fInn\fP to save a series of
- Xfiles in separate, unique files. All that is required is that the
- Xfile name contains an asterisk, e.g.
- X.br
- X +src/hype/part*.shar
- X.br
- XThis will cause each of the articles to be saved in separate, unique
- Xfiles named part1.shar, part2.shar, and so on, always choosing a part
- Xnumber that results in a unique file name (i.e. if part1.shar did
- Xalready exist, the first article would be saved in part2.shar, the
- Xnext in part3.shar, and so on).
- X.LP
- X\fBRelated variables\fP:
- Xdefault-save-file, folder, save-counter, save-counter-offset.
- X.SH FILE AND GROUP NAME COMPLETION
- XWhen entering a file name or a news group name, a simple
- X.B completion
- Xfeature is available using the \fBspace\fP, \fBtab\fP, and \fB?\fP keys.
- X.LP
- XHitting \fBspace\fP anywhere during input will complete the
- X.I current
- X.I component
- Xof the file name or group name with the
- X.I first
- Xavailable possibility.
- X.LP
- XIf this possibility is not the one you want, keep on hitting
- X.B space
- Xuntil it appears.
- X.LP
- XWhen the right completion has appeared, you can just continue typing
- Xthe file or group name, or you can hit
- X.B tab
- Xto fix the current component, and get the
- X.I first
- Xpossibility for the next component, and then use
- X.B space
- Xto go through the other possible completions.
- X.LP
- XThe
- X.B ?
- Xkey will produce a list of the possible
- X.I completions
- Xof the current component. If the list is too long for the available
- Xspace on screen, the key can be repeated to get the next part of the
- Xlist.
- X.LP
- XThe current completion can be deleted with the
- X.B erase
- Xkey.
- X.LP
- XThe default value for a file name is the last file name you have
- Xentered, so if you enter a
- X.B space
- Xas the first character after the prompt, the last file name will be
- Xrepeated (and you can edit it if you like). In some cases, a string
- Xwill already be written for you in the prompt line, and to get the
- Xdefault value in these cases, use the \fBkill\fP key. This also means
- Xthat if you neither want the initial value, nor the default value, you
- Xwill have to hit the \fBkill\fP twice to get a clean prompt line.
- X.LP
- X\fBRelated variables\fP:
- Xcomp1-key, comp2-key, help-key, suggest-default-save.
- X.SH POSTING AND RESPONDING TO ARTICLES
- XIn both selection mode and reading mode you can post new articles,
- Xpost follow-ups to articles, send replies to the author of an article,
- Xand you can send mail to another user with the option of including an
- Xarticle in the letter. In reading mode, a response is made to the
- Xcurrent article, while in selection mode you will be prompted for an
- Xarticle to respond to.
- X.LP
- XThe following commands are available (the lower-case equivalents are
- Xalso available in reading mode):
- X.TP
- X\&\fBR\fP {\fBreply\fP}
- XReply through mail to the author of the article. This is the prefered
- Xway to respond to an article unless you think your reply is of general
- Xinterest.
- X.TP
- X\&\fBF\fP {\fBfollow\fP}
- XFollow-up with an article in the same newsgroup (unless an alternative
- Xgroup is specified in the article header).
- X.TP
- X\&\fBM\fP {\fBmail\fP}
- XMail a letter or
- X.I forward
- Xan article to a single recipient.
- XIn selection mode, you will be prompted for an article to include
- Xin your letter, and in reading mode you will be asked if the current
- Xarticle should be included in the letter.
- XYou will then be prompted for the recipient of the letter (default
- Xrecipient is yourself)
- Xand the subject of the letter (if an article is included, you may hit
- X.B space
- Xto get the default subject which is the subject of the included article).
- X The header of the article is only included in the posted letter if
- Xit is forwarded (i.e. not edited), or if the variable
- X\fBinclude-full-header\fP is set.
- X.TP
- X\&\fB:post\fP {\fBpost\fP}
- XPost a new article to any newsgroup. This command will prompt you for
- Xa
- X.I comma-separated
- Xlist of newsgroups to post to (you cannot enter a space because
- X.B space
- Xis used for group name completion as described below).
- X.LP
- XGenerally, \fInn\fP will construct a file with a suitable header, optionally
- Xinclude a copy of the article in the file with each non-empty line
- Xprefixed by a `>' character (except in mail mode), and invoke an
- Xeditor of your choice (using the EDITOR environment variable) on this
- Xfile, positioning you on the first line of the body of the article (if
- Xit knows the editor).
- X.PP
- XWhen you have completed editing the message, it will compare it to the
- Xunedited file, and if they are identical (i.e. you did not make any
- Xchanges to the file), or it is empty, the operation is cancelled.
- XOtherwise you will be prompted for an action to take on the
- Xconstructed article (enter first letter followed by \fBreturn\fP, or
- Xjust \fBreturn\fP to take the default action):
- X.br
- X.sp 0.5v
- X Action: a)bort e)dit i)spell r)eedit s)end v)iew w)rite (send)
- X.sp 0.5v
- X.br
- XYou now have the opportunity to perform one of the following actions:
- X.LP
- X.in +2m
- X.ta 5m
- X.\"ta 4 9
- X\fBa\fP throw the response away (will ask for confirmation),
- X.br
- X\fBe\fP edit the file again,
- X.br
- X\fBi\fP run an (interactive) \fBspell-checker\fP on the text,
- X.br
- X\fBr\fP throw away the edited text and edit the original text,
- X.br
- X\fBs\fP send the article or letter,
- X.br
- X\fBv\fP view the article (through the \fBpager\fP), or
- X.br
- X\fBw\fP append it to a file (before you send it).
- X.in -2m
- X.DT
- X.LP
- X\fBRelated variables\fP:
- Xappend-signature-mail, append-signature-post, default-distribution,
- Xedit-response-check, editor, include-art-id, include-full-header,
- Xincluded-mark, mail-header, mail-record, mail-script, mailer,
- Xmailer-pipe-input, news-header, news-record, news-script,
- Xorig-to-include-mask, pager, query-signature,
- Xrecord, response-check-pause, response-default-answer,
- Xsave-counter, save-counter-offset, save-report, spell-checker.
- X.SH JUMPING TO OTHER GROUPS
- XBy default \fInn\fP will present the news groups in a predefined
- Xsequence (see the section on Presentation Sequence later on).
- XTo override this sequence and have a look at any other group the
- X.B G
- X{\fBgoto-group\fP} command available in both selection and reading
- Xmode enables you to move freely between all the newsgroups.
- X.LP
- XFurthermore, the
- X.B G
- Xcommand enables you to open folders and other files, to read old
- Xarticles you have read before, and to grep for a specific subject in a
- Xgroup.
- X.PP
- XIt is important to notice that normally the goto command is recursive,
- Xi.e. a new \fImenu level\fP is created when the specified group or
- Xfolder is presented, and when it has been read, \fInn\fP will continue
- Xthe activity in the group that was presented before the goto command
- Xwas executed. However, if there are unread articles in the target
- Xgroup you can avoid entering a new menu level by using the
- X.B j
- Xreply described below. The current menu level (i.e. number of nested
- Xgoto commands) will be shown in the prompt line as "<N>" (in reverse
- Xvideo).
- X.PP
- XThe goto command is very powerful, but unfortunately also a little bit
- Xtricky at first sight, because the facilities it provides depend on
- Xthe context in which the command is used.
- X.PP
- XWhen executed, the goto command will prompt you for the name of the
- Xnewsgroup, folder, or file to open. It will use the first letter
- Xyou enter to distinguish these three possibilities:
- X.TP
- X.B return
- XAn empty answer is equivalent to the current newsgroup.
- X.TP
- X\fIletter\fP
- XThe answer is taken to be the name of a newsgroup.
- X.TP
- X.I +
- X.br
- XThe answer is taken to be the name of a folder. If only `+' is
- Xentered, it is equivalent to the default save file for the current
- Xgroup.
- X.TP
- X\fI\&/ or ./ or ~/\fP
- XThe answer is taken to be the name of a file, either relative to the
- Xcurrent directory, relative to your home directory, or an absolute
- Xpath name for the file.
- X.TP
- X.B %
- XIn reading mode, this reply corresponds to reading the current article
- X(and splitting it as a digest). In selection mode, it will prompt for
- Xan article on the menu to read.
- X.TP
- X.B @
- XThis choice is equivalent to the archive file for the current group.
- X\fInnmaster\fP maintains archive files with all old and current
- Xarticles for the groups which have the auto-archive option set in the
- XGROUPS file (see \fInnmaster\fP(8)).
- X.TP
- X\fB=\fP and \fInumber\fP
- XThese answers are equivalent to the same answers described below
- Xapplied to the current group (e.g. \fBG return =\fP and \fBG =\fP are
- Xquivalent).
- X.LP
- XSpecifying a folder, a file, or an article (with \fB%\fP) will cause
- X\fInn\fP to treat the file like a digest and split it into separate
- Xarticles (not physically!) which are then presented on a menu in the
- Xusual way, allowing you to read or save individual subarticles from
- Xthe folder.
- X.LP
- XWhen you enter a group name, \fInn\fP will ask you how many articles
- Xin the group you want to see on the menu. You can give the following
- Xanswers:
- X.TP
- X.I a number N
- XIn this case you will get the newest N articles in the group, or if
- Xyou specified the current group (by hitting \fBreturn\fP to the group
- Xname prompt or entering the number directly), you will get that many
- X\fIextra\fP articles included on the same menu (without creating a new
- Xmenu level).
- X.TP
- X.B j
- XThis answer can only be given if there are unread articles in the
- Xgroup. It will instruct nn to jump directly to the specified group in
- Xthe presentation sequence \fIwithout\fP creating a new menu level.
- X.TP
- X.B u
- XThis instructs \fInn\fP to present the \fIunread\fP articles in the
- Xgroup (if there are any). If you have already read the group (in the
- Xcurrent invocation of \fInn\fP), the \fBu\fP answer will instruct
- X\fInn\fP to present the articles that were unread when you entered
- X\fInn\fP.
- X.TP
- X.B a
- XThis instruct \fInn\fP to present \fBall\fP articles in the group.
- X.TP
- X\fBs\fP\fIword\fP or \fB=\fP\fIword\fP
- XThis instructs \fInn\fP to search \fIall\fP articles in the groups,
- Xbut only present the articles containing the word \fIword\fP in the
- Xsubject. Notice that case is ignored when searching for the word in
- Xthe subject lines.
- X.TP
- X\fBn\fP\fIword\fP
- XSame as the \fBs\fP form except that it searched for articles where
- Xthe sender \fIname\fP matches \fIword\fP.
- X.TP
- X\fBe\fP\fIword\fP
- XSame as the \fBs\fP form except that it Psearched for articles where
- X\fIeither\fP the subject or the sender name matches \fIword\fP.
- X.TP
- X\fIword\fP = \fB/\fP\fIregexp\fP
- XWhen the first character of the \fIword\fP specified with the \fBs\fP,
- X\fBn\fP, and \fBe\fP forms is a slash `/', the rest of the input is
- Xinterpreted as a regular expression to search for. Notice that
- Xregular expression matching is case insensitive when
- X\fBcase-fold-search\fP is set (default).
- X.TP
- X.B return
- XThe meaning of an empty answer depends on the context: if there are
- Xunread articles in the specified group the unread articles will be
- Xpresented, otherwise \fIall\fP articles in the group will be included
- Xin the menu.
- X.LP
- XIf you specified the current group, and the menu already contains all
- Xthe available articles, \fInn\fP will directly prompt for a word to
- Xsearch for in the subject of all articles (the prompt will be an equal
- Xsign.)
- X.LP
- XWhen the goto command creates a new menu level, \fInn\fP will not
- Xperform auto kill or selection in the group. You can use the \fB+\fP
- Xcommand in menu mode to perform the auto-selections.
- X.LP
- XThere are three commands in the goto family:
- X.TP
- X\&\fBG\fP {\fBgoto-group\fP}
- XThis is the general goto command described above.
- X.TP
- X\&\fBB\fP {\fBback-group\fP}
- XBackup one or more groups. You can hit this key one or more times to
- Xgo back in the groups already presented (including those without new
- Xarticles); when you have found the group you are looking for, hit
- X\fBspace\fP to enter it.
- X.TP
- X\&\fBA\fP {\fBadvance-group\fP}
- XAdvance one or more groups. This command is similar to the \fBB\fP
- Xcommand, but operates in the opposite direction.
- X.TP
- X\&\fBN\fP {\fBnext-group\fP}
- XWhen used within an \fBA\fP or \fBB\fP command, it skips forward to
- Xthe next group in the sequence with unread articles or which has
- Xpreviously been visited.
- X.TP
- X\&\fBP\fP {\fBprevious\fP}
- XWhen used within an \fBA\fP or \fBB\fP command, it skips backwards to
- Xthe preceding group in the sequence with unread articles or which has
- Xpreviously been visited.
- X.LP
- XOnce you have entered an \fBA\fP or \fBB\fPcommand, you can freely mix
- Xthe \fBA\fP, \fBB\fP, \fBP\fP, and \fBN\fP commands to find the group
- Xyou want, and you can also use the \fBG\fP command to be prompted for
- Xa group name.
- X.LP
- XTo show the use of the goto command some typical examples on
- Xits use are given below:
- X.sp
- X.nf
- X.I "Present the unread articles in the dk.general group"
- X.sp 0.5v
- X \fBG\fP dk.general \fBreturn\fP \fBu\fP
- X.sp
- X.I "Jump directly to the gnu.emacs group and continue from there"
- X.sp 0.5v
- X \fBG\fP gnu.emacs \fBreturn\fP \fBj\fP
- X.sp
- X.I "Include the last 10 READ articles in the current group menu"
- X.sp 0.5v
- X \fBG\fP 10 \fBreturn\fP
- X.sp
- X.I "Find all articles in rec.music.misc on the subject Floyd"
- X.sp 0.5v
- X \fBG\fP rec.music.misc \fBreturn\fP
- X \fB=\fP floyd \fBreturn\fP
- X.sp 0.5v
- X.sp
- X.I "Open the folder +nn"
- X.sp 0.5v
- X \fBG\fP +nn \fBreturn\fP
- X.sp
- X.I "Split current article as a digest (in reading mode)"
- X.sp 0.5v
- X \fBG\fP \fB%\fP
- X
- X.fi
- X.LP
- X\fBRelated variables\fP:
- Xcase-fold-search, default-save-file
- X.SH AUTOMATIC KILL AND SELECTION
- XWhen there is a subject or an author which you are either very
- Xinterested in, or find completely uninteresting, you can easily
- Xinstruct \fInn\fP to \fIauto-select\fP or \fIauto-kill\fP articles
- Xwith specific subjects or from specific authors. These instructions
- Xare stored in a \fIkill file\fP, and the most common types of entries
- Xcan be created using the following command:
- X.TP
- X\&\fBK\fP {\fBkill-select\fP}
- XCreate an entry in your personal kill file. The contents of the entry
- Xis specified during a short dialog that is described in details below.
- XThis command is available in both selection and reading mode.
- X.LP
- XEntries in the kill file may apply to a single newsgroup or to all
- Xnewsgroups. Furthermore, entries may be permanent or they may be
- Xexpired a given number of days after their entry.
- X.LP
- XTo increase performance, \fInn\fP uses a compiled version of the kill
- Xfile which is read in when \fInn\fP is invoked. The compiled kill
- Xfile will automatically be updated if the normal kill file has been
- Xmodified.
- X.LP
- XThe following dialog is used to build the kill file entry:
- X.TP
- X\fIAUTO (k)ill or (s)elect (CR => Kill subject 1 month)\fP
- XIf you simply want \fInn\fP to kill all articles with the subject of
- Xthe current article (in reading mode) or a specific article (which
- X\fInn\fP will prompt for in selection mode), just hit \fBreturn\fP.
- XThis will cause \fInn\fP to create an entry in the kill file to kill
- Xthe current (or specified) subject in the current group for a period
- Xof 30 days (which should be enough for the discussion to die out).
- X.sp 0.5v
- XIf this "default behaviour" is not what you want, just answer either
- X\fIk\fP or \fIs\fP to kill or select articles, respectively, which
- Xwill bring you on to the rest of the questions.
- X.TP
- X\fIAUTO SELECT on (s)ubject or (n)ame (s)\fP
- X(The \fISELECT\fP will be substituted with \fIKILL\fP depending on the
- Xprevious answer). Here you specify whether you want the kill or
- Xselect to depend on the subject of the article (\fBs\fP or
- X\fBspace\fP), or on the name of the author (\fBn\fP).
- X.TP
- X\fISELECT NAME:\fP
- X(Again \fISELECT\fP may be substituted with \fIKILL\fP and
- X\fISUBJECT\fP may replace \fINAME\fP). You must now enter a name (or
- Xsubject) to select (or kill). In reading mode, you may just hit
- X\fBreturn\fP (or \fB%\fP) to use the name (or subject) of the current
- Xarticle. In selection mode, you can use the name (or subject) from an
- Xarticle on the menu by answering with \fB%\fP followed by the
- Xcorresponding article identifier.
- X.sp 0.5v
- XWhen the name or subject is taken from an article (the current or one
- Xfrom the menu), \fInn\fP will only select or kill articles where the
- Xname or subject matches the original name or subject exactly including
- Xcase.
- X.sp 0.5v
- XIf the first character typed at the prompt is a slash `/', the rest of
- Xthe line is used as a \fIregular expression\fP which is used to match
- Xthe name or subject (case \fIin\fPsensitive).
- X.sp 0.5v
- XOtherwise, \fInn\fP will select or kill articles which \fIcontain\fP
- Xthe specified string anywhere in the name or subject (ignoring case).
- X.TP
- X\fISELECT in (g)roup `dk.general' or in (a)ll groups (g)\fP
- XYou must now specify whether the selection or kill should apply to the
- Xcurrent group only (\fBg\fP or \fBspace\fP) or to all groups (\fBa\fP).
- X.TP
- X\fILifetime of entry in days (p)ermanent (30)\fP
- XYou can now specify the lifetime of the entry, either by entering a
- Xnumber specifying the number of days the entry should be active, or
- X\fBp\fP to specify the entry as a permanent entry. An empty reply is
- Xequivalent to 30 days.
- X.TP
- X\fICONFIRM SELECT ....\fP
- XFinally, you will be asked to confirm the entry, and you should
- Xespecially note the presence or absence of the word \fBexact\fP which
- Xspecify whether an exact match applies for the entry.
- X.LP
- X\fBRelated variables\fP:
- Xkill.
- X.SH THE FORMAT OF THE KILL FILE
- XThe kill file consists of one line for each entry. Empty lines and
- Xlines starting with a # character are ignored. \fInn\fP automatically
- Xplaces a # character in the first position of expired entries when it
- Xcompiles the kill file. You can then edit the kill file manually from
- Xtime to time to clean out these entries.
- X.LP
- XEach line has the following format
- X.br
- X [\fIexpire time\fP :] [\fIgroup name\fP] : \fIflags\fP : \fIstring\fP [: \fIstring\fP]...
- X.br
- X.LP
- XPermanent entries have no \fIexpire time\fP (in which case the colon
- Xis omitted as well!). Otherwise, the \fIexpire time\fP defines the
- Xtime (as a time_t value) when the entry should be expired.
- X.LP
- XThe \fIgroup name\fP field can have three forms:
- X.TP
- X\fInews.group.name\fP
- XIf it is the name of a single news group (e.g. comp.unix),
- Xthe entry applies to that group only.
- X.TP
- X\fB/\fP\fIregular expression\fP
- XIf it starts with a slash `/' followed by a \fIregular expression\fP
- X(e.g. /^news\e..*), the entry applies to all groups whose name are
- Xmatched by the regular expression.
- X.TP
- X\fIempty\fP
- XAn empty group field will apply the entry to \fIall\fP groups.
- X.LP
- XThe \fIflags\fP field consists of a list of characters which
- Xidentifies the type of entry, and the interpretation of each
- X\fIstring\fP field. When used, the flag characters must be used in
- Xthe order in which they are desctibed below:
- X.TP
- X\fB~\fP (optional)
- X.br
- XWhen this flag is present on any of the entries for a specific group,
- Xit causes all entires which \fIare not auto-selected\fP to be killed.
- XThis is a simple way to say: I'm interested in this and that, but
- Xnothing else.
- X.TP
- X\fB+\fP or \fB!\fP (optional)
- X.br
- XSpecify an auto-select \fB+\fP or an auto-kill \fB!\fP entry,
- Xrespectively. If neither are used, the article is neither selected
- Xnor killed which is useful in combination with the `\fB~\fP' flag.
- X.LP
- XFor each \fIstring\fP, the \fIflags\fP field must contain the following
- Xcharacters defining the interpretation of the corresponding
- X\fIstring\fP:
- X.TP
- X\fBn\fP or \fBs\fP (mandatory)
- X.br
- XSpecify whether the corresponding string applies to the name \fBn\fP
- Xor to the subject \fBs\fP of an article.
- X.TP
- X\fB/\fP (optional)
- X.br
- XSpecifies that the corresponding \fIstring\fP is a \fBregular expression\fP
- Xwhich the sender or subject is matched against. If not specified, a simple
- Xstring match is performed using the given \fIstring\fP.
- X.TP
- X\fB=\fP (optional)
- X.br
- XSpecifies that the match against the name or subject is \fIcase
- Xsensitive\fP. Furthermore, when regular expression matching
- Xis \fInot\fP used, the name or subject must be of the same length
- Xof the \fIstring\fP to match.
- XOtherwise, the match will be case insensitive, and a \fIstring\fP may
- Xoccur anywhere in the name or subject to match.
- X.TP
- X\fB|\fP or \fB&\fP (mandatory if multiple strings)
- X.br
- XIf more than one string is specified, the set of \fIflags\fP
- Xcorresponding to each \fIstring\fP must be separated by either an
- X\fIor operator\fP `\fB|\fP' or an \fIand operator\fP `\fB&\fP'. The
- Xand operator has a higher precedence than the or operator, e.g. a
- Xcomplex match expression \fIa|b&c|d\fP will succeed if either of
- X\fIa\fP, \fIb&c\fP, or \fId\fP matches.
- X.LP
- XThe \fIstring\fP field in the entry is the name, subject or regular
- Xexpression that will be matched against the name or subject of each
- Xarticle in the group (or all groups). Colons and backslashes must be
- Xescaped with a backslash in the string.
- X.LP
- XExample 1: Auto-select articles from `Tom Collins' (exact) on subject
- X`News' in all groups:
- X.sp 0.5v
- X :+n=&s:Tom Collins:News
- X.sp
- XExample 2: Kill all articles which are neither from `Tom' or `Eve' in
- Xsome.group. Select only articles from Eve:
- X.sp 0.5v
- X some.group:~n:Tom
- X.br
- X some.group:+n:Eve
- X.sp
- XThe second example can also be written as a single entry with an or
- Xoperator (in this case, the select/kill attribute only applies to the succeeding strings):
- X.br
- X some.group:~n|+n:Tom:Eve
- X.LP
- XTo remove expired entries, to "undo" a \fBK\fP command, and to make
- Xthe more advanced entries with more than one string, you will have to
- Xedit the kill file manually. To recompile the file, you can use the
- X\fB:compile\fP command. When you invoke \fInn\fP, it will also
- Xrecompile the kill file if the compiled version is out of dat.
- X.SH SHELL ESCAPES
- XThe
- X.B !
- Xcommands available in selection and reading mode are identical in
- Xoperation (with one exception). When you enter the shell escape
- Xcommand, you will be prompted for a shell command. This command will
- Xbe fed to the shell specified in the \fBshell\fP variable (default
- Xloaded from the SHELL environment variable or /bin/sh) after the
- Xfollowing substitutions have been performed on the command:
- X.TP
- X\fIFile name expansion\fP
- XThe ealier described file name expansions will be performed on all
- Xarguments.
- X.TP
- X.B $G
- Xwill be substituted with the name of the current news group.
- X.TP
- X.B $L
- Xwill be substituted with the \fIlast component\fP of the name of the
- Xcurrent news group.
- X.TP
- X.B $F
- Xwill be substituted with the name of the current news group with the
- Xperiods replaced by slashes.
- X.TP
- X.B $N
- Xwill be substituted with the (local) article number (only defined in
- Xreading mode).
- X.TP
- X.B $A
- Xis replaced by the full path name of the file containing the current article
- X(only defined in reading mode).
- X.TP
- X.B %
- XSame as $A.
- X.TP
- X.B $(VAR)
- Xis replaced by the string value of the environment variable \fIVAR\fP.
- X.LP
- XWhen the shell command is completed, you will be asked to hit any key
- Xto continue. If you hit the
- X.B !
- Xkey again, you will be prompted for a new shell command. Any other
- Xkey will redraw the screen and return you to the mode you came from.
- X.LP
- X\fBRelated variables\fP:
- Xshell, shell-restrictions.
- X.SH MISCELLANEOUS COMMANDS
- XBelow are more useful commands which are available in both
- Xselection and reading modes.
- X.TP
- X\&\fBU\fP {\fBunsub\fP}
- XUnsubscribe to the current group. You will not see this group
- Xanymore unless you explicitly request it. If the variable
- X\fBunsubscribe-mark-read\fP is set, all articles in the group will be
- Xmarked read when you unsubscribe.
- X If the variable \fBkeep-unsubscribed\fP is not set, the group will
- Xbe removed from .newsrc. If you are not subscribing to the group, you
- Xwill be given the possibility to \fIresubscribe\fP to the group! This
- Xmay be used in connection with the \fBG\fP command to resubscribe a
- Xgroup.
- X.TP
- X\&\fBC\fP {\fBcancel\fP}
- XCancel (delete) an article in the current group or folder. Cancelling
- Xarticles in a folder will cause the folder to be rewritten when it is
- Xclosed. In selection mode, you will be prompted for the identifier of
- Xthe article to cancel. Normal users can only cancel their own
- Xarticles.
- X.TP
- X\&\fBY\fP {\fBoverview\fP}
- XProvide an overview of the groups with unread articles.
- X.TP
- X\&\fB"\fP {\fBlayout\fP}
- XChange menu layout in selection mode. The menu will be redrawn using
- Xthe next layout (cycling through ..., 2, 3, 4, 0, 1, ...)
- X.LP
- XMost of the commands in \fInn\fP are bound to a key and can be activated
- Xby a single keystroke. However, there are a few commands that
- Xcannot be bound to a key directly.
- X.LP
- XAs shown in the keystroke command descriptions, all commands have a
- Xname, and it is possible to activate a command by name with the
- X\fIextended command\fP key (\fB:\fP). Hitting this key will prompt
- Xyou for the name of a command (and parameters). For example, an
- Xalternative to hitting the \fBR\fP key to reply to an article is to
- Xenter the extended command \fB:reply\fP followed by \fBreturn\fP. The
- X\fB:post\fP and \fB:unshar\fP commands described earlier can also be
- Xbound to a key. The complete list of commands which can be bound to
- Xkeys is provided in the section on Key Mappings below.
- X.LP
- XThe following extended commands \fIcannot\fP be bound to a key, mainly
- Xbecause they require additional parameters on the prompt line, or
- Xbecause it should not be possible to activate them too easily.
- X.TP
- X\fB:admin\fP
- XEnter administrative mode. This is identical in operation to the
- X.IR nnadmin (1M)
- Xprogram.
- X.TP
- X\fB:bug\fP
- XPrepare and send a bug report to the nn-bugs mailing address.
- X.TP
- X\fB:cd\fP [ \fIdirectory\fP ]
- XChange current working directory. If the directory argument is not provided,
- X\fInn\fP will prompt for it.
- X.TP
- X\fB:compile\fP
- XRecompile the \fIkill\fP file. This is not necessary under normal
- Xoperation since \fInn\fP automatically compiles the file on start-up
- Xif it has changed, but it can be used if you modify the kill file
- Xwhile \fInn\fP is suspended.
- X.TP
- X\fB:coredump\fP
- XAbort with a core dump. For debugging purposes only.
- X.TP
- X\fB:define\fP \fImacro\fP
- XDefine macro number \fImacro\fP as described in the Macro Definition
- Xsection below. If \fImacro\fP is omitted, the next free macro number
- Xwill be chosen.
- X.TP
- X\fB:dump\fP \fItable\fP
- XSame as the \fB:show\fP command described below.
- X.TP
- X\fB:help\fP [ \fIsubject\fP ]
- XProvide online help on the specified subject. If you omit the
- Xsubject, a list of the available topics will be given.
- X.TP
- X\fB:local\fP \fIvariable\fP [ \fIvalue\fP ]
- XMake the variable local to the current group. Subsequent changes to
- Xthe variable will only be effective until the current group is left.
- XIf a value is specified, it will be assigned to the local variable.
- XTo assign a new value to a boolean variable, the values \fBon\fP and
- X\fBoff\fP must be used.
- X.TP
- X\fB:man\fP
- XCall up the online manual. The manual is presented as a normal folder
- Xwith the program name in the `From' field and the section title in the
- X\&`subject' field. All the normal commands related to a folder works
- Xfor the online manual as well, e.g. you can save and print sections of
- Xthe manual.
- X.TP
- X\fB:map\fP \fIarguments\fP
- XThis is the command used for binding commands to the keys. It is
- Xfully described in the Key Mapping section below.
- X.TP
- X\fB:mkdir\fP [ \fIdirectory\fP ]
- XCreate the directory (and the directories in its path). It will
- Xprompt for at directory name if the argument is omitted.
- X.TP
- X\fB:pwd\fP
- XPrint path name of current working directory on message line.
- X.TP
- X\fB:q\fP
- XHas no effect besides redrawing the screen if necessary. If an
- Xextended command (one which is prefixed by a :) produces any output
- Xrequirering the screen to be redrawn, the screen will not be redrawn
- Ximmediately if the variable \fBdelayed-redraw\fP is set (useful on
- Xslow terminals). Instead another \fB:\fP prompt is shown to allow you
- Xto enter a new extended command immediately. It is sufficient to hit
- X.B return
- Xto redraw the screen, but it has been my experience that entering
- X.B q return
- Xin this situation happens quite often, so it was made a no-op.
- X.TP
- X\fB:q!\fP
- XQuit \fInn\fP without updating the \fB.newsrc\fP file.
- X.TP
- X\fB:Q\fP
- XQuit \fInn\fP. This is equivalent to the normal
- X.B Q
- Xcommand.
- X.TP
- X\fB:rmail\fP
- XOpen your mailbox (see the \fBmail\fP variable) as a folder to
- Xread the incoming messages. This is \fInot\fP a full mail interface
- X(you cannot delete messages, no cc: on replies, etc), but it can give
- Xyou a quick glance at new mail without leaving \fInn\fP.
- X.TP
- X\fB:set\fP \fIvariable\fP [ \fIvalue\fP ]
- XSet a boolean variable to true or assign the value to a string or
- Xinteger variable. The
- X.B :set
- Xcommand is described in details in the section on VARIABLES.
- X.TP
- X\fB:sh\fP
- XSuspend \fInn\fP, or if that is not possible, spawn an interactive shell.
- X.TP
- X\fB:show groups\fP \fImode\fP
- XShow the total number or the number of unread articles in the current
- Xgroup, depending on \fImode\fP: \fBall\fP (list the number of unread
- Xarticles in all groups including groups which you have unsubscribed
- Xto), \fBtotal\fP (list the total number of articles in all existing
- Xgroups), \fBunsub\fP (list unsubscribed groups only). Any other
- X\fImode\fP results in a listing of the number of unread articles in
- Xall subscribed groups including those you have suppressed with the `!'
- Xsymbol in the group presentation sequence. To get just the currently
- Xunread groups in the presentation sequence, use the `Y'
- X{\fBoverview\fP} command.
- X.TP
- X\fB:show kill\fP
- XShow the kill entries that applies to the current group and to all groups.
- X.TP
- X\fB:show rc\fP [ \fIgroup\fP ]
- XShow the .newsrc and select file entries for the current or the
- Xspecified group.
- X.TP
- X\fB:show map\fP [ \fImode\fP ]
- XShow the key bindings in the current or specified mode.
- X.TP
- X\fB:sort\fP [ \fImode\fP ]
- XReorder the articles on the menu according to \fImode\fP or if omitted
- Xto the default \fBsort-mode\fP. The following sorting modes are
- Xavailable: \fBarrival\fP (list articles in the order in which they
- Xarrived on the system), \fBsubject\fP (articles with identical
- Xsubjects are grouped and ordered after age of the oldest article in
- Xthe group), lexical (subjects in lexicographical order), \fBage\fP
- X(articles ordered after posting date only), and \fBsender\fP (articles
- Xordered after sender's name).
- X.TP
- X\fB:unset\fP \fIvariable\fP
- XToggle a boolean variable.
- X.TP
- X\fB:unread\fP [ \fIgroup\fP ] [ \fIarticles\fP ]
- XMark the current (or specified) group as unread. If the
- X\fIarticles\fP argument is omitted, the number of unread articles in
- Xthe group will be set to the number of unread articles when \fInn\fP
- Xwas invoked. Otherwise, the argument specifies the number of unread
- Xarticles.
- X.TP
- X\fB:unset\fP \fIvariable\fP
- XSet a boolean variable to false or clear an integer variable.
- X.TP
- X\fB:x\fP
- XQuit \fInn\fP and \fBmark\fP all articles in the current group as
- X\fIread\fP!
- X.LP
- X\fBRelated variables\fP:
- Xbackup, bug-report-address, delayed-redraw, keep-unsubscribed,
- Xunsubscribe-mark-read, mail, pager, sort-mode.
- X.\" ENDPART B
- END_OF_FILE
- if test 32572 -ne `wc -c <'man/nn.1.B'`; then
- echo shar: \"'man/nn.1.B'\" unpacked with wrong size!
- fi
- # end of 'man/nn.1.B'
- fi
- if test -f 'master.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'master.c'\"
- else
- echo shar: Extracting \"'master.c'\" \(19338 characters\)
- sed "s/^X//" >'master.c' <<'END_OF_FILE'
- X/*
- X * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
- X *
- X * nn database daemon (nnmaster)
- X *
- X * maintains the article header database.
- X */
- X
- X#include <signal.h>
- X#include <errno.h>
- X#include "config.h"
- X#include "db.h"
- X#include "proto.h"
- X
- Ximport char *bin_directory;
- X
- X/*
- X * nnmaster options:
- X *
- X * -e [N] expire a group if more than N articles are gone
- X * -r N repeat every N minutes
- X *
- X * -f foreground execution (use with -r)
- X * -y N retry N times on error
- X *
- X * -E [N] expire mode (see expire.c) [N==1 if omitted]
- X * -F Run ONLY expire ONCE and exit.
- X * -R N auto-recollect mode (see expire.c)
- X *
- X * -C check consistency of database on start-up
- X * -b include 'bad' articles (disables -B)
- X * -B remove 'bad' articles (just unlink the files)
- X * -O N Consider articles older than N days as bad articles.
- X *
- X * -I [N] initialize [ limit to N articles in each group ]
- X * -G reread groups file.
- X * -X clean ignored groups.
- X *
- X * -l"MSG" lock database with message MSG
- X * -l unlock database
- X * -i ignore lock (run collection on locked database)
- X * -k kill the running master and take over.
- X *
- X * -Q quiet: don't write fatal errors to /dev/console (if no syslog).
- X * -t trace collection of each group
- X * -v print version and exit
- X * -u update even if active is not modified
- X * -w send wakeup to real master
- X * -Ltypes exclude 'types' entries from the log
- X * -D [N] debug, N = +(1 => verbose, 2 => nntp trace)
- X *
- X * [master group]... Collect these groups only.
- X */
- X
- X#include "options.h"
- X
- X
- Ximport int
- X dont_write_console,
- X expire_method,
- X expire_level,
- X recollect_method,
- X reread_groups_file,
- X ignore_bad_articles,
- X#ifdef NNTP
- X nntp_local_server,
- X nntp_debug,
- X#endif
- X remove_bad_articles,
- X retry_on_error;
- X
- Ximport time_t
- X max_article_age;
- X
- Ximport char
- X *log_entry_filter;
- X
- Xexport int
- X trace = 0,
- X debug_mode = 0,
- X#ifdef NNTP
- X silent = 1,
- X no_update = 0,
- X#endif
- X Debug = 0;
- X
- Xstatic int
- X check_on_startup = 0,
- X clean_ignored = 0,
- X expire_once = 0,
- X foreground = 0,
- X ignore_lock = 0,
- X initialize = -1,
- X kill_running = 0,
- X max_age_days = 0,
- X prt_vers = 0,
- X unconditional = 0,
- X wakeup_master = 0;
- X
- Xstatic unsigned
- X repeat_delay = 0;
- X
- X
- Xstatic char
- X *lock_message = NULL;
- X
- X
- XOption_Description(master_options) {
- X
- X 'b', Bool_Option( ignore_bad_articles ),
- X 'B', Bool_Option( remove_bad_articles ),
- X 'C', Bool_Option( check_on_startup ),
- X 'D', Int_Option_Optional( debug_mode, 1 ),
- X 'e', Int_Option_Optional( expire_level, 1 ),
- X 'E', Int_Option_Optional( expire_method, 1 ),
- X 'f', Bool_Option( foreground ),
- X 'F', Bool_Option( expire_once ),
- X 'G', Bool_Option( reread_groups_file ),
- X#ifdef NNTP
- X 'H', Bool_Option( nntp_local_server ),
- X#endif
- X 'i', Bool_Option( ignore_lock ),
- X 'I', Int_Option_Optional( initialize, 0 ),
- X 'k', Bool_Option( kill_running ),
- X 'l', String_Option_Optional( lock_message, "" ),
- X 'L', String_Option( log_entry_filter ),
- X 'O', Int_Option( max_age_days ),
- X 'Q', Bool_Option( dont_write_console ),
- X 'r', Int_Option_Optional( repeat_delay, 10 ),
- X 'R', Int_Option( recollect_method ),
- X 't', Bool_Option( trace ),
- X 'u', Bool_Option( unconditional ),
- X 'v', Bool_Option( prt_vers ),
- X 'w', Bool_Option( wakeup_master ),
- X 'X', Bool_Option( clean_ignored ),
- X 'y', Int_Option( retry_on_error ),
- X '\0',
- X};
- X
- Ximport char *master_directory, *db_directory, *news_active;
- X
- Xstatic int unlock_on_exit = 0;
- X
- X/*
- X * nn_exit() --- called whenever a program exits.
- X */
- X
- Xnn_exit(n)
- X{
- X#ifdef NNTP
- X if (use_nntp) nntp_cleanup();
- X#endif /* NNTP */
- X close_master();
- X
- X if (unlock_on_exit)
- X proto_lock(I_AM_MASTER, PL_CLEAR);
- X
- X if (n)
- X log_entry('E', "Abnormal termination, exit=%d", n);
- X else
- X if (unlock_on_exit)
- X log_entry('M', "Master terminated%s", s_hangup ? " (hangup)" : "");
- X
- X exit(n);
- X}
- X
- X
- Xstatic clean_group_internal(gh) /* no write */
- Xregister group_header *gh;
- X{
- X gh->first_db_article = 0;
- X gh->last_db_article = 0;
- X
- X if (gh->data_write_offset > (off_t)0) {
- X gh->data_write_offset = (off_t)0;
- X (void)open_data_file(gh, 'd', -1);
- X }
- X
- X if (gh->index_write_offset) {
- X gh->index_write_offset = (off_t)0;
- X (void)open_data_file(gh, 'x', -1);
- X }
- X
- X gh->master_flag &= ~(M_EXPIRE | M_BLOCKED);
- X if ((gh->master_flag & M_IGNORE_GROUP) == 0)
- X gh->master_flag |= M_BLOCKED;
- X
- X}
- X
- Xclean_group(gh) /* does write */
- Xgroup_header *gh;
- X{
- X if (trace)
- X log_entry('T', "CLEAN %s", gh->group_name);
- X if (debug_mode)
- X printf("CLEAN %s\n", gh->group_name);
- X
- X clean_group_internal(gh);
- X
- X db_write_group(gh);
- X}
- X
- Xextern long collect_group();
- Xextern long expire_group();
- X
- Xstatic char **restrictions = NULL;
- Xstatic int *restr_len, *restr_excl;
- X
- Xstatic group_restriction(gh)
- Xregister group_header *gh;
- X{
- X register char **rp;
- X register int *lp, *xp;
- X
- X if (restrictions == NULL) return;
- X
- X for (rp = restrictions, lp = restr_len, xp = restr_excl; *lp > 0; rp++, lp++, xp++)
- X if (strncmp(gh->group_name, *rp, *lp) == 0) {
- X if (*xp) break;
- X return;
- X }
- X
- X if (*lp == 0) return;
- X
- X gh->master_flag |= M_IGNORE_G;
- X}
- X
- Xstatic set_group_restrictions(restr, n)
- Xchar **restr;
- Xint n;
- X{
- X register group_header *gh;
- X register int i;
- X
- X restrictions = restr;
- X restr_len = newobj(int, n + 1);
- X restr_excl = newobj(int, n);
- X
- X for (i = 0; i < n; i++) {
- X if (restrictions[i][0] == '!') {
- X restr_excl[i] = 1;
- X restrictions[i]++;
- X } else
- X restr_excl[i] = 0;
- X restr_len[i] = strlen(restrictions[i]);
- X }
- X
- X restr_len[n] = -1;
- X
- X Loop_Groups_Header(gh) {
- X if (gh->master_flag & M_IGNORE_GROUP) continue;
- X group_restriction(gh);
- X if (clean_ignored && (gh->master_flag & M_IGNORE_G)) {
- X log_entry('X', "Group %s ignored", gh->group_name);
- X clean_group(gh);
- X }
- X }
- X}
- X
- X/*
- X * add new group to master file
- X */
- X
- Xgroup_header *add_new_group(name)
- Xchar *name;
- X{
- X register group_header *gh;
- X
- X if (master.free_groups <= 0)
- X db_expand_master();
- X
- X master.free_groups--;
- X
- X gh = &active_groups[master.number_of_groups];
- X
- X gh->group_name_length = strlen(name);
- X gh->group_name = copy_str(name);
- X
- X gh->group_num = master.number_of_groups++;
- X gh->creation_time = cur_time();
- X
- X db_append_group(gh);
- X
- X group_restriction(gh); /* done after append to avoid setting ! */
- X clean_group(gh);
- X
- X db_write_master();
- X
- X sort_groups();
- X
- X log_entry('C', "new group: %s (%d)", gh->group_name, gh->group_num);
- X
- X return gh;
- X}
- X
- X
- Xstatic visit_active_file()
- X{
- X FILE *act;
- X FILE *nntp_act = NULL;
- X
- X#ifdef NNTP
- X if (!use_nntp) /* copy 'active' to DB/ACTIVE */
- X nntp_act = open_file(relative(db_directory, "ACTIVE"), OPEN_CREATE | MUST_EXIST);
- X#endif
- X
- X act = open_file(news_active, OPEN_READ|MUST_EXIST);
- X
- X read_active_file(act, nntp_act);
- X
- X master.last_size = ftell(act);
- X
- X fclose(act);
- X
- X#ifdef NNTP
- X if (nntp_act != NULL) fclose(nntp_act);
- X#endif
- X}
- X
- X
- X/*
- X * Build initial master file.
- X */
- X
- Xstatic build_master()
- X{
- X char command[512];
- X char groupname[512];
- X group_header *groups, *next_g, *gh;
- X FILE *src;
- X int lcount, use_group_file, found_nn_group = 0;
- X
- X printf("Confirm initialization by typing 'OK': ");
- X fl;
- X gets(command);
- X if (strcmp(command, "OK")) {
- X printf("No initialization\n");
- X nn_exit(0);
- X }
- X
- X if (chdir(master_directory) < 0) /* so we can use open_file (?) */
- X sys_error("master");
- X
- X#ifdef NNTP
- X if (use_nntp && nntp_get_active() < 0)
- X sys_error("Can't get active file");
- X#endif
- X /* check active file for duplicates */
- X
- X sprintf(command, "awk 'NF>0{print $1}' %s | sort | uniq -d", news_active);
- X
- X src = popen(command, "r");
- X if (src == NULL)
- X sys_error("popen(%s) failed", command);
- X
- X for (lcount = 0; fgets(groupname, 512, src); lcount++) {
- X if (lcount == 0)
- X printf("\n%s contains duplicate entries for the following groups:",
- X news_active);
- X
- X fputs(groupname, stdout);
- X }
- X
- X pclose(src);
- X
- X if (lcount > 0) {
- X printf("Do you want to repair this file before continuing ? (y)");
- X gets(command);
- X if (s_hangup ||
- X command[0] == NUL || command[0] == 'y' || command[0] == 'Y')
- X nn_exit(0);
- X }
- X
- X /* if a "GROUPS" file exist offer to use that, else */
- X /* read group names from active file */
- X
- X use_group_file = 0;
- X
- X if (open_groups(OPEN_READ)) {
- X printf("\nA GROUPS file already exist -- reuse it? (y)");
- X fl;
- X gets(command);
- X if (command[0] == NUL || command[0] == 'y' || command[0] == 'Y') {
- X use_group_file = 1;
- X } else
- X close_groups();
- X if (s_hangup) return;
- X }
- X
- X printf("\nBuilding %s/MASTER file\n", db_directory);
- X fl;
- X
- X if (!use_group_file) {
- X sprintf(command, "awk 'NF>0{print $1}' %s | sort -u", news_active);
- X
- X src = popen(command, "r");
- X if (src == NULL)
- X sys_error("popen(%s) failed", command);
- X }
- X
- X open_master(OPEN_CREATE);
- X
- X master.db_magic = NNDB_MAGIC;
- X master.last_scan = 0;
- X master.number_of_groups = 0;
- X strcpy(master.db_lock, "Initializing database");
- X
- X db_write_master();
- X
- X groups = next_g = newobj(group_header, 1);
- X next_g->next_group = NULL;
- X
- X for (;;) {
- X if (s_hangup) goto intr;
- X gh = newobj(group_header, 1);
- X
- X gh->master_flag = 0;
- X
- X if (use_group_file) {
- X gh->group_name_length = 0;
- X if (db_parse_group(gh, 0) <= 0) break;
- X } else {
- X if (fgets(groupname, 512, src) == NULL) break;
- X
- X gh->group_name_length = strlen(groupname) - 1; /* strip NL */
- X groupname[gh->group_name_length] = NUL;
- X gh->creation_time = 0;
- X gh->group_name = copy_str(groupname);
- X gh->archive_file = NULL;
- X }
- X
- X gh->group_num = master.number_of_groups++;
- X
- X if (trace || debug_mode)
- X printf("%4d '%s' (%d)\n", gh->group_num, gh->group_name,
- X gh->group_name_length);
- X
- X next_g->next_group = gh;
- X next_g = gh;
- X gh->next_group = NULL;
- X
- X init_group(gh); /* for clean_group() */
- X
- X /* moderation flag will be set by first visit_active_file call */
- X
- X if (strcmp(gh->group_name, "control") == 0)
- X gh->master_flag |= M_CONTROL;
- X
- X if (strcmp(gh->group_name, "news.software.nn") == 0)
- X found_nn_group++;
- X
- X gh->master_flag &= ~M_MUST_CLEAN;
- X clean_group_internal(gh);
- X gh->master_flag |= M_VALID; /* better than the reverse */
- X db_write_group(gh);
- X }
- X
- X if (use_group_file)
- X close_groups();
- X else
- X pclose(src);
- X
- X printf("%s %s/GROUPS file\n",
- X use_group_file ? "Updating" : "Building", db_directory);
- X sprintf(command, "cd %s ; [ -f GROUPS ] && (rm -f GROUPS~ ; mv GROUPS GROUPS~)",
- X db_directory);
- X system(command);
- X
- X open_groups(OPEN_CREATE|MUST_EXIST);
- X
- X for (gh = groups->next_group; gh != NULL; gh = gh->next_group)
- X db_append_group(gh);
- X
- X close_groups();
- X
- X if (initialize > 0) {
- X printf("Setting articles per group limit to %d...\n", initialize);
- X db_write_master();
- X open_master(OPEN_READ);
- X open_master(OPEN_UPDATE);
- X visit_active_file();
- X Loop_Groups_Header(gh) {
- X gh->first_db_article = gh->last_a_article - initialize + 1;
- X if (gh->first_db_article <= gh->first_a_article) continue;
- X gh->last_db_article = gh->first_db_article - 1;
- X if (gh->last_db_article < 0) gh->last_db_article = 0;
- X db_write_group(gh);
- X }
- X }
- X
- X master.db_lock[0] = NUL;
- X master.db_created = cur_time();
- X
- X db_write_master();
- X
- X close_master();
- X
- X printf("Done\n");
- X fl;
- X
- X log_entry('M', "Master data base initialized");
- X
- X if (!found_nn_group)
- X printf("\nNotice: nn's own news group `news.software.nn' was not found\n");
- X
- X return;
- X
- X intr:
- X printf("\nINTERRUPT\n\nDatabase NOT completed\n");
- X log_entry('M', "Master data base initialization not completed (INTERRUPTED)");
- X}
- X
- Xstatic set_lock_message()
- X{
- X open_master(OPEN_UPDATE);
- X db_read_master();
- X if (lock_message[0] || master.db_lock[0]) {
- X strncpy(master.db_lock, lock_message, DB_LOCK_MESSAGE);
- X master.db_lock[DB_LOCK_MESSAGE-1] = NUL;
- X db_write_master();
- X printf("DATABASE %sLOCKED\n", lock_message[0] ? "" : "UN");
- X }
- X}
- X
- Xstatic do_reread_groups()
- X{
- X register group_header *gh;
- X
- X open_master(OPEN_UPDATE);
- X Loop_Groups_Header(gh)
- X if (gh->master_flag & M_MUST_CLEAN) {
- X gh->master_flag &= ~M_MUST_CLEAN;
- X clean_group(gh);
- X } else
- X db_write_group(gh);
- X master.last_scan = 0;
- X db_write_master();
- X close_master();
- X log_entry('M', "Reread GROUPS file");
- X}
- X
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X register group_header *gh;
- X time_t age_active;
- X int group_selection;
- X int temp;
- X
- X umask(002); /* avoid paranoia */
- X
- X who_am_i = I_AM_MASTER;
- X
- X init_global();
- X
- X group_selection =
- X parse_options(argc, argv, (char *)NULL, master_options, (char *)NULL);
- X
- X if (debug_mode) {
- X#ifdef NNTP
- X nntp_debug = debug_mode & 2;
- X#endif
- X debug_mode = debug_mode & 1;
- X }
- X
- X if (debug_mode) {
- X extern sig_type catch_hangup();
- X signal(SIGINT, catch_hangup);
- X }
- X
- X if (wakeup_master) {
- X if (proto_lock(I_AM_MASTER, PL_WAKEUP) < 0)
- X printf("master is not running\n");
- X exit(0);
- X }
- X
- X if (prt_vers) {
- X printf("nnmaster release %s\n", version_id);
- X exit(0);
- X }
- X
- X if (kill_running) {
- X for (temp = 10; --temp >= 0; sleep(3))
- X if (proto_lock(I_AM_MASTER, PL_TERMINATE) < 0) break;
- X
- X if (temp < 0) {
- X printf("The running master will not die....!\n");
- X log_entry('E', "Could not kill running master");
- X exit(1);
- X }
- X
- X if (repeat_delay == 0 && !foreground &&
- X !reread_groups_file && lock_message == NULL &&
- X group_selection == 0 && initialize < 0)
- X exit(0);
- X }
- X
- X if (proto_lock(I_AM_MASTER, PL_SET) != 0) {
- X printf("The master is already running\n");
- X exit(0);
- X }
- X unlock_on_exit = 1;
- X
- X#ifdef NNTP
- X nntp_check();
- X#endif
- X
- X if (initialize >= 0) {
- X build_master();
- X nn_exit(0);
- X }
- X
- X if (lock_message != NULL) {
- X set_lock_message();
- X if (repeat_delay == 0 && !foreground &&
- X !reread_groups_file && group_selection == 0)
- X nn_exit(0);
- X }
- X
- X open_master(OPEN_READ);
- X
- X if (!ignore_lock && master.db_lock[0]) {
- X printf("Database locked (unlock with -l or ignore with -i)\n");
- X nn_exit(88);
- X }
- X
- X if (reread_groups_file) {
- X do_reread_groups();
- X nn_exit(0);
- X }
- X
- X if (!debug_mode) {
- X close(0);
- X close(1);
- X close(2);
- X if (open("/dev/null", 2) == 0) dup(0), dup(0);
- X }
- X
- X if (repeat_delay && !debug_mode && !foreground) {
- X while ((temp = fork()) < 0) sleep(1);
- X if (temp) exit(0); /* not nn_exit() !!! */
- X
- X process_id = getpid(); /* init_global saved parent's pid */
- X
- X proto_lock(I_AM_MASTER, PL_TRANSFER);
- X
- X#ifdef DETATCH_TERMINAL
- X DETATCH_TERMINAL
- X#endif
- X }
- X
- X log_entry('M', "Master started -r%d -e%d %s-E%d",
- X repeat_delay, expire_level,
- X expire_once ? "-F " : "", expire_method);
- X
- X if (check_on_startup) {
- X char cmd[FILENAME];
- X sprintf(cmd, "%s/nnadmin Z", bin_directory);
- X system(cmd);
- X log_entry('M', "Database validation completed");
- X }
- X
- X repeat_delay *= 60;
- X
- X init_digest_parsing();
- X
- X open_master(OPEN_UPDATE);
- X
- X if (group_selection)
- X set_group_restrictions(argv + 1, group_selection);
- X
- X if (max_age_days && !use_nntp) /* we have to stat spool files */
- X max_article_age = cur_time() - (time_t)max_age_days * 24 * 60 * 60;
- X else
- X max_article_age = 0;
- X
- X if (expire_once) {
- X if (group_selection) /* mark selected groups for expire */
- X Loop_Groups_Header(gh) {
- X if (gh->master_flag & M_IGNORE_GROUP) continue;
- X gh->master_flag |= M_EXPIRE;
- X }
- X unconditional = 1;
- X }
- X
- X for (;;) {
- X#ifdef NNTP
- X if (use_nntp && nntp_get_active() < 0) {
- X nntp_close_server();
- X current_group = NULL; /* for init_group */
- X log_entry('N', "Can't access active file --- %s",
- X repeat_delay ? "sleeping" : "terminating");
- X if (repeat_delay == 0)
- X nn_exit(1);
- X sleep(repeat_delay);
- X continue;
- X }
- X#endif
- X
- X age_active = file_exist(news_active, "fr");
- X if (!use_nntp && age_active == (time_t)0)
- X sys_error("Cannot access active file");
- X
- X if (unconditional) {
- X master.last_scan = age_active - 60;
- X unconditional = 0;
- X }
- X
- X if (!receive_admin() && age_active <= master.last_scan) {
- X if (repeat_delay == 0) break;
- X if (s_hangup) break;
- X#ifdef NNTP
- X if (use_nntp) nntp_cleanup();
- X#endif
- X if (debug_mode) {
- X printf("NONE (*** SLEEP ***)\n");
- X continue;
- X }
- X
- X if (trace) log_entry('T', "none");
- X sleep(repeat_delay);
- X if (s_hangup) break;
- X continue;
- X }
- X
- X visit_active_file();
- X
- X if (do_expire())
- X if (!expire_once && do_collect())
- X master.last_scan = age_active;
- X
- X db_write_master();
- X
- X if (expire_once || s_hangup) break;
- X if (repeat_delay == 0) break;
- X
- X#ifdef NNTP
- X if (use_nntp) nntp_cleanup();
- X#endif
- X if (!debug_mode) sleep(repeat_delay);
- X if (s_hangup) break;
- X }
- X
- X nn_exit(0);
- X /*NOTREACHED*/
- X}
- X
- X
- X
- X/*
- X * receive commands from administrator
- X */
- X
- Xreceive_admin()
- X{
- X FILE *gate;
- X char buffer[128], *bp;
- X char command, opt, *user_date;
- X int32 arg;
- X int must_collect;
- X register group_header *gh;
- X
- X gate = open_file(relative(master_directory, "GATE"), OPEN_READ | OPEN_UNLINK);
- X if (gate == NULL) return 0;
- X
- X sleep(2); /* give administrator time to flush buffers */
- X
- X must_collect = 0;
- X
- X while (fgets(buffer, 128, gate)) {
- X bp = buffer;
- X
- X command = *bp++;
- X if (*bp++ != ';') continue;
- X
- X arg = atol(bp);
- X if (arg >= master.number_of_groups) continue;
- X gh = (arg >= 0) ? &active_groups[arg] : NULL;
- X if ((bp = strchr(bp, ';')) == NULL) continue;
- X bp++;
- X
- X opt = *bp++;
- X if (*bp++ != ';') continue;
- X
- X arg = atol(bp);
- X if ((bp = strchr(bp, ';')) == NULL) continue;
- X
- X user_date = ++bp;
- X if ((bp = strchr(bp, ';')) == NULL) continue;
- X *bp++ = NUL;
- X if (*bp != NL) continue;
- X
- X log_entry('A', "RECV %c %s %c %ld (%s)",
- X command, gh == NULL ? "(all)" : gh->group_name, opt, arg, user_date);
- X
- X switch (command) {
- X
- X case SM_SET_OPTION:
- X switch (opt){
- X case 'r':
- X repeat_delay = arg;
- X continue;
- X case 'e':
- X expire_level = arg;
- X continue;
- X case 't':
- X trace = (arg < 0) ? !trace : arg;
- X continue;
- X }
- X
- X case SM_EXPIRE:
- X if (gh) {
- X gh->master_flag |= M_EXPIRE | M_BLOCKED;
- X db_write_group(gh);
- X break;
- X }
- X Loop_Groups_Header(gh) {
- X if (gh->master_flag & M_IGNORE_GROUP) continue;
- X if (gh->index_write_offset == 0) continue;
- X if (gh->master_flag & M_EXPIRE) continue;
- X gh->master_flag |= M_EXPIRE;
- X db_write_group(gh);
- X }
- X break;
- X
- X case SM_SET_FLAG:
- X if (opt == 's')
- X gh->master_flag |= (flag_type)arg;
- X else
- X gh->master_flag &= ~(flag_type)arg;
- X db_write_group(gh);
- X continue;
- X
- X case SM_RECOLLECT: /* recollect */
- X if (gh) {
- X if ((gh->master_flag & M_IGNORE_GROUP) == 0)
- X clean_group(gh);
- X } else
- X Loop_Groups_Header(gh)
- X if ((gh->master_flag & M_IGNORE_GROUP) == 0)
- X clean_group(gh);
- X break;
- X
- X case SM_SCAN_ONCE: /* unconditional pass */
- X unconditional++;
- X break;
- X
- X default:
- X continue;
- X }
- X must_collect = 1;
- X }
- X
- X fclose(gate);
- X
- X return must_collect;
- X}
- X
- X
- Xwrite_error()
- X{
- X /*
- X * should wait for problems to clear out rather than die...
- X */
- X sys_error("DISK WRITE ERROR");
- X}
- X
- X/*
- X * dummy routines - should never be called by master
- X */
- X
- X/*VARARGS*/
- Xuser_error()
- X{
- X dummy_error("user_error");
- X}
- X
- Xdummy_error(name)
- Xchar *name;
- X{
- X sys_error("Dummy routine called by master: %s", name);
- X}
- X
- X#ifdef HAVE_JOBCONTROL
- Xsuspend_nn()
- X{}
- X#endif
- X
- X#ifdef NNTP /* XXX */
- X/*VARARGS*/
- Xmsg() {}
- Xuser_delay(n) {}
- X#endif /* NNTP Bogus */
- END_OF_FILE
- if test 19338 -ne `wc -c <'master.c'`; then
- echo shar: \"'master.c'\" unpacked with wrong size!
- fi
- # end of 'master.c'
- fi
- echo shar: End of archive 7 \(of 22\).
- cp /dev/null ark7isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 22 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
-
- exit 0 # Just in case...
-